/**
 * Controller class for Flashlight+
 *
 * LICENSE: This source file is subject to the MIT License, available
 * at http://www.opensource.org/licenses/mit-license.html
 *
 * @author     Jayson Schmidt <jayson@888mobileapps.com>
 * @copyright  2013 888MobileApps
 * @license    http://www.opensource.org/licenses/mit-license.html
 */

package com.threeeightmobileapps.flashlightplus;

import java.util.Timer;
import java.util.TimerTask;

import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

public class FlashlighPlusController extends View {

	/**
	 * Variables
	 */
	
	private boolean update;
	private boolean onOff;
	
	private int mode;
	
	private float fontSize;
	
	private long mPeriod;
	
	private String statusText;
	
	private Camera camera;
	private Context context;
	private PackageManager pm;
	private Parameters params;
	
	private Timer mUpdateTimer;	
	
	private Paint mPaint = new Paint();
	private Paint c = new Paint();
	
	/**
	 * Constructors
	 */
	
	public FlashlighPlusController (Context c) {
		super(c);
		context = c;
	}
	
	public FlashlighPlusController (Context c, AttributeSet attrs) {
		super(c, attrs);
		context = c;
	}
	
	/**
	 * Public Methods
	 */
	
	/**
	 * Initializes parameters
	 */
	public void init() {
		onOff = false;
		mPeriod = 50;
		update = false;
		mPaint.setTextSize(75);
		mPaint.setTextAlign(Paint.Align.CENTER);
		fontSize = mPaint.getTextSize();
		c.setStyle(Style.STROKE);
		c.setStrokeWidth(10);
		updateStatusText(false);
		pm = context.getPackageManager();
		if(checkHardware()) {
			camera = Camera.open();
			params = camera.getParameters();
		}
		setMode(1);
		invalidate();
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if(event.getAction() == MotionEvent.ACTION_DOWN) {
			switch (getMode()) {
			case 1:
				turnOnOff();
				break;
			case 2:
				if(update) {
					update = false;
					stopUpdateTimer();
					updateStatusText(false);
					lightOff();
				} else {
					update = true;
					updateStatusText(true);
					startUpdateTimer();
				}
				break;
			case 3:
				onOff = true;
				updateStatusText(true);
				lightOn();
				break;
			default:
				break;
			}
			c.setStrokeWidth(15);
			invalidate();
			return true;
		}
		
		if(event.getAction() == MotionEvent.ACTION_UP) {
			if(getMode() == 3) {
				onOff = false;
				updateStatusText(false);
				lightOff();
			}
			c.setStrokeWidth(10);
			invalidate();
			return true;
		}
		
		invalidate();
		return super.onTouchEvent(event);
	}
	
	/**
	 * Accessor Methods
	 */
	
	/**
	 * Sets current mode
	 * 
	 * @param m Status 1: flashlight mode
	 * 				   2: strobe mode
	 * 				   3: Morse code mode
	 */
	public void setMode(int m) {
		mode = m;
		if(update) {
			update = false;
			stopUpdateTimer();
		}
		
		onOff = false;
		lightOff();
		updateStatusText(false);
		invalidate();
	}
	
	/**
	 * Returns current mode
	 * 
	 * @return The current mode
	 */
	public int getMode() {
		return mode;
	}
	
	/**
	 * Class Methods
	 */
	
	/**
	 * Checks to see if the device has the required hardware (a flash).
	 * 
	 * @return boolean False if appropriate hardware isn't found, true otherwise.
	 */
	private boolean checkHardware() {
		boolean check = true;
		if(!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {
			Toast.makeText(context, 
					"No flash detected", 
					Toast.LENGTH_LONG);
			check = false;
		}
		
		return check;
	}
	
	/**
	 * Toggles onOff based on current value
	 */
	private void turnOnOff() {
		if(onOff) {
			onOff = false;
			if(mode != 2)
				updateStatusText(false);
			lightOff();
		}else {
			onOff = true;
			if(mode != 2)
				updateStatusText(true);
			lightOn();
		}
	}
	
	/**
	 * Turns on device flash
	 */
	private void lightOn() {
		params.setFlashMode(Parameters.FLASH_MODE_TORCH);
		camera.setParameters(params);
	}
	
	/**
	 * Turns off device flash
	 */
	private void lightOff() {
		params.setFlashMode(Parameters.FLASH_MODE_OFF);
		camera.setParameters(params);
	}
	
	/**
	 * Updates status text on screen (On/Off)
	 * 
	 * @param b Boolean status value
	 */
	private void updateStatusText(boolean b) {
		if(b) {
			mPaint.setARGB(255, 255, 255, 255);
			statusText = "ON";
		}else {
			mPaint.setARGB(255, 125, 125, 125);
			statusText = "OFF";
		}
	}
	
	/**
	 * Updates the value of update
	 * 
	 * @param b Boolean update value
	 */
	private void setUpdate(boolean b) {
		this.update = b;
	}
	
	private class UpdateTask extends TimerTask {
		public void run() {
			setUpdate(true);
			turnOnOff();
		}
	}
	
	/**
	 * Starts update timer
	 */
	protected void startUpdateTimer() {
		mUpdateTimer = new Timer();
		mUpdateTimer.schedule(new UpdateTask(), 0, mPeriod);
	}
	
	/**
	 * Stops update timer
	 */
	protected void stopUpdateTimer() {
		if(mUpdateTimer != null) {
			mUpdateTimer.cancel();
		}
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		canvas.drawText(statusText,
				(this.getWidth()/2), 
				this.getHeight()/2 + fontSize/3, 
				mPaint);
		c.setColor(mPaint.getColor());

		canvas.drawCircle(this.getWidth()/2, 
				this.getHeight()/2, 
				fontSize*2, 
				c);
		
	}
}
